<template>
  <view class="tabs-el" :style="{'background-color':bgColor}">
    <slot name="left" />
    <view class="tabs-el-wrapper" :class="{ border }">
      <scroll-view
        :scroll-x="scrollable"
        :scroll-left="scrollLeft"
        scroll-with-animation
        enable-flex
        enable-passive
        class="scroll-view-nav"
        :class="{ evenly: !scrollable && evenly }"
        :show-scrollbar="false">
        <view
          v-for="(item, index) in list"
          :key="index"
          class="scroll-view-nav-item"
          @click="clickHandler(item, index)"
          :style="[$u.addStyle(itemStyle), { flex: flexStyle }]"
          :class="[{ disabled: item.disabled, active: index == innerCurrent }]">
          <text>
            {{ item[keyName] }}
          </text>
          <u-badge
            v-if="item.badge"
            :show="item.badge.show || item.badge.isDot || item.badge.value"
            :isDot="item.badge.isDot"
            :value="item.badge.value"
            :max="item.badge.max"
            :type="item.badge.type"
            :showZero="item.badge.showZero"
            :bgColor="item.badge.bgColor"
            :color="item.badge.color"
            :shape="item.badge.shape"
            :numberType="item.badge.numberType"
            :inverted="item.badge.inverted"
            customStyle="margin-left: 4px;" />
        </view>
      </scroll-view>
      <view class="scroll-view-nav-line" :style="[navLineStyle]"></view>
    </view>
    <slot name="right" />
  </view>
</template>

<script>
function toFixed(number, digit = 2) {
  const value = 10 ** digit;
  return Math.round(number * value) / value;
}
export default {
  name: "tabs-el",
  props: {
    // 滑块的移动过渡时间，单位ms
    duration: {
      type: Number,
      default: 300,
    },
    // tabs标签数组
    list: {
      type: Array,
      default: () => [],
    },
    // 滑块颜色
    lineColor: {
      type: String,
      default: "#3c9cff",
    },
    // 菜单选择中时的样式
    activeStyle: {
      type: [String, Object],
      default: () => ({ color: "#303133" }),
    },
    // 菜单非选中时的样式
    inactiveStyle: {
      type: [String, Object],
      default: () => ({ color: "#606266" }),
    },
    // 滑块长度(默认用)
    lineWidth: {
      type: [String, Number],
      default: 20,
    },
    // 滑块高度
    lineHeight: {
      type: [String, Number],
      default: 3,
    },
    // 滑块背景显示大小，当滑块背景设置为图片时使用
    lineBgSize: {
      type: String,
      default: "cover",
    },
    // 菜单item的样式
    itemStyle: {
      type: [String, Object],
      default: () => ({}),
    },
    // 菜单是否可滚动
    scrollable: {
      type: Boolean,
      default: false,
    },
    // 当前选中标签的索引
    current: {
      type: [Number, String],
      default: 0,
    },
    // 默认读取的键名
    keyName: {
      type: String,
      default: "name",
    },
    autoWidth: {
      //line自动宽度
      type: Boolean,
      default: false,
    },
    evenly: {
      //item平分宽度
      type: Boolean,
      default: false,
    },
    border: {
      //添加下划线
      type: Boolean,
      default: false,
    },
	bgColor: {
      type: String,
      default: "#fff",
    },
  },
  data() {
    return {
      scrollLeft: 0,
      lineOffsetLeft: 0,
      innerCurrent: 0,
      $lineWidth: 0, //设置用
    };
  },
  computed: {
    navLineStyle() {
      const lineWidth = this[`${this.autoWidth ? "$" : ""}lineWidth`];
      return {
        width: uni.$u.addUnit(lineWidth),
        transform: `translate(${this.lineOffsetLeft}px)`,
        transitionDuration: `${this.duration}ms`,
        height: uni.$u.addUnit(this.lineHeight),
        background: this.lineColor,
        backgroundSize: this.lineBgSize,
      };
    },
    flexStyle() {
      return this.evenly || this.scrollable ? "" : "1";
    },
  },
  methods: {
    clickHandler(item, index) {
      this.innerCurrent = index;
      this.$emit("change", { ...item, index });
    },
    resize() {
      this.$uGetRect(".scroll-view-nav-item", true).then(async res => {
        this.boundaryCoordinates = []; //边界坐标
        this.boundaryWidth = [];
        this.rightBoundary = res[res.length - 1].right;
        const fn = number => Math.floor(number * 100) / 100;
        for (const item of res) {
          this.boundaryCoordinates.push(fn(item.left));
          this.boundaryWidth.push(fn(item.width));
        }
        if (this.scrollable) {
          //如果可滚动,则获取导航菜单的尺寸
          this.tabsRect = await this.$uGetRect(".scroll-view-nav");
          this.isBeyondBorder = this.rightBoundary > this.tabsRect.width; //是否超出边界
        }
        this.updateMove();
      });
    },
    async updateMove() {
      let offsetLeft = this.boundaryCoordinates[this.innerCurrent];
      let diffWidth = 0;
      const currentWidth = this.boundaryWidth[this.innerCurrent];
      //超出总宽才需要移动scroll-view
      if (this.isBeyondBorder) {
        // 将活动的tabs-item移动到屏幕正中间，实际上是对scroll-view的移动
        const leftWidth = offsetLeft + currentWidth / 2; //左宽[左边界+一半的itemWidth]
        const tabsLeftWidth = this.tabsRect.width / 2; //tabs宽度一半
        if (leftWidth > tabsLeftWidth) {
          //判断移动位置是否超过一半
          this.scrollLeft = toFixed(leftWidth - tabsLeftWidth); //scroll-view移动位置
          if (leftWidth + tabsLeftWidth >= this.rightBoundary) {
            //判断是否超出总宽(右半接近末尾时)
            diffWidth = tabsLeftWidth + leftWidth - this.rightBoundary; //差值宽度
          }
        } else {
          this.scrollLeft = 0; //如果没有超过一半则不移动scroll-view,只移动line
        }
      }
      if (this.autoWidth) {
        this.$lineWidth = currentWidth;
      } else {
        //非自动宽度需要获取原计算值
        if (!this.$$lineWidth) {
          this.$$lineWidth = (
            await this.$uGetRect(".scroll-view-nav-line")
          ).width;
        }
        //lineMove的距离增加currentWidth-line剩余左宽度,使line保持居中
        offsetLeft += (currentWidth - this.$$lineWidth) / 2;
      }
      this.lineOffsetLeft = toFixed(offsetLeft - this.scrollLeft + diffWidth);
    },
  },
  watch: {
    list() {
      this.resize();
    },
    current: {
      immediate: true,
      handler(index) {
        this.innerCurrent = index;
      },
    },
    innerCurrent() {
      if (this.lineOffsetLeft <= 0) {
        this.resize();
      } else {
        this.$nextTick(this.updateMove);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.tabs-el {
  display: flex;
  align-items: center;
  &-wrapper {
    position: relative;
    flex: 1;
    height: 88rpx;
    /* #ifndef APP-NVUE */
    overflow: auto hidden;
    /* #endif */
    &.border {
      border-bottom: 1px solid #e2e2e2;
    }
    .scroll-view-nav {
      display: flex;
      height: 100%;
      &.evenly {
        justify-content: space-evenly;
      }
      &-item {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0 22rpx;
        flex-shrink: 0;
        > text {
          font-size: 30rpx;
          color: $u-content-color;
          transition: color 0.3s;
        }
        &.active > text {
          color: $u-theme-color;
        }
        &.disabled {
          /* #ifndef APP-NVUE */
          cursor: not-allowed;
          /* #endif */
          > text {
            color: $u-disabled-color;
          }
        }
      }
      &-line {
        position: absolute;
        height: 6rpx;
        background: $u-theme-color;
        width: 60rpx;
        bottom: 2rpx;
        border-radius: 100px;
        transition-property: transform, width;
        transition-duration: 300ms;
      }
    }
  }
}
</style>
